
#include<sys/epoll.h>
#include<functional>

class Channel
{
private:
    using EventCallBack = std::function<void()>;
    int _fd;             //文件描述符
    uint32_t _events;    //监控的事件
    uint32_t _revents;   //就绪的事件
    EventCallBack _read_cb;     //读事件回调
    EventCallBack _write_cb;    //写事件回调
    EventCallBack _error_cb;    //错误事件回调
    EventCallBack _close_cb;    //挂断事件回调        一般来说，挂断事件和错误事件的处理方式是一样的
    EventCallBack _event_cb;    //任意事件回调 
    //EventLoop* _loop   //后续会添加的成员
private:
    //私有接口，用于真正和 Poller 模块和 EventLoop 模块联动，进行事件监控的调整
    void UpdateEvents()  //op 就是未来传递给 epoll_ctl 的op参数
    {
        //后续调用EventLoop提供的接口
        //_loop->UpdateEvents();
    }
public:
    Channel(int fd):_fd(fd),_events(0),_revents(0){}
    //启动读事件监控
    int Fd()const{return _fd;}//用于获取文件描述符 
    uint32_t Events()const{return _events;}
    void EnableRead()
    {
        if(HasRead())  return ;//说明已经监控了读事件了 
        _events|= EPOLLIN;
        UpdateEvents(); 
    }
    //是否启动了读事件
    bool HasRead()const
    {
        return _events & EPOLLIN;
    }
    //取消读事件监控
    void DisableRead()
    {
        if(!HasRead()) return ; //说明本来就没有监控读事件
        _events &= (~EPOLLIN);
        UpdateEvents();
    }
    //启动写事件监控
    void EnableWrite()
    {
        if(HasWrite()) return ;
        _events |= EPOLLOUT;
        UpdateEvents();
    }
    //是否启动了写事件
    bool HasWrite()const
    {
        return _events & EPOLLOUT;
    }
    //取消写事件监控
    void DisableWwrite()
    {
        if(!HasWrite()) return;
        _events &= (~EPOLLOUT);
        UpdateEvents();
    }
    //取消所有事件监控
    void DisableAll()
    {
        _events = 0;
        UpdateEvents();
    }
    //移除监控
    void Remove()
    {
        DisableAll();
        //调用_loop提供的Remove接口
    }
    //设置就绪事件
    void SetRevents(uint32_t revents){_revents = revents;}
    //处理就绪事件
    void HandlerEvents()
    {
        //读事件需要处理
        if(_revents & (EPOLLIN | EPOLLPRI | EPOLLRDHUP))  
        {
            if(_read_cb) _read_cb();
            if(_event_cb) _event_cb(); //任意事件触发都需要调用，防止事件
        }
        //剩下三个事件只需要处理其中一种
        if(_revents & EPOLLOUT)
        {
            if(_event_cb) _event_cb();  //因为写事件可能会关闭连接，所以没办法，我们只能放在前面调用了
            if(_write_cb) _write_cb();
        }
        else if(_revents & EPOLLHUP)
        {
            if(_event_cb) _event_cb();
            if(_close_cb) _close_cb();
        }
        else if(_revents & EPOLLERR)
        {
            if(_event_cb) _event_cb();
            if(_close_cb) _close_cb();
        }
        return;
    }
    //设置读事件回调
    void SetReadCallBack(const EventCallBack& cb){ _read_cb = cb;}
    //设置写事件回调
    void SetWriteCallBack(const EventCallBack& cb){ _write_cb = cb;}
    //设置错误事件回调
    void SetErrorCallBack(const EventCallBack& cb){ _error_cb = cb;}
    //设置挂断事件回调
    void SetCloseCallBack(const EventCallBack& cb){ _close_cb = cb;}
    //设置任意事件回调
    void SetEventCallBack(const EventCallBack& cb){ _event_cb = cb;}
};
